﻿// *----------------------------------------------------------------
// Copyright (C) 2017 通通优品
// 版权所有。
// 
// 类名：TransactionScopeConnections.cs
// 功能描述：TongTongMall.Dapper
// 
// Create User：jym 2017/02/09
// 
// Edit User：UserName,EditTime
// Describe：Describe
// ----------------------------------------------------------------*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Remoting.Messaging;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Transactions;
using TongTongMall.Dapper;
using TongTongMall.Dapper.DapperExtensions;

namespace TongTongMall.Dapper
{
    public class TransactionScopeConnections<TDatabase> where TDatabase : IDatabase
    {
        /// <summary>
        /// 在不同线程中，且同一个IIS请求发生时保证连接针对当前上下文为统一实例
        /// </summary>
        static readonly Dictionary<Transaction, Dictionary<string, DatabaseConnectionWrapper>> transactionConnections =
            new Dictionary<Transaction, Dictionary<string, DatabaseConnectionWrapper>>();

        /// <summary>
        /// 线程内数据对象数据对象
        /// </summary>
        //static readonly Dictionary<string, DatabaseConnectionWrapper> connectionNoTransactionList =
        //   new Dictionary<string, DatabaseConnectionWrapper>();

        public const string ConnectionListKey = "TongTongMall.ConnectionList.Current";

        /// <summary>
        /// 在作用域内返回一个dbconnection
        /// </summary>
        /// <param name="db"></param>
        /// <returns></returns>
        public static DatabaseConnectionWrapper GetConnection(DapperDbContextProvider<TDatabase> db)
        {
            //var aaat = Thread.CurrentPrincipal;
            //var aaa = CallContext.HostContext;
            //Transaction currentTransaction = Transaction.Current;
            //var dbtest = CallContext.LogicalGetData("test1") as DatabaseConnectionWrapper;
            ////保证一次线程内获取到的DBConectionn是一个对象，最后统一释放。
            //if (currentTransaction == null)
            //{
            //    if (dbtest != null) return dbtest;
            //    DatabaseConnectionWrapper noTransactionConnection;
            //    lock (connectionNoTransactionList)
            //    {
            //        //线程同步
            //        if (!connectionNoTransactionList.TryGetValue(db.ConnectionString, out noTransactionConnection))
            //        {
            //            var dbConnection = db.GetNewOpenConnection();
            //            noTransactionConnection = new DatabaseConnectionWrapper(dbConnection);
            //            CallContext.LogicalSetData("test1", noTransactionConnection);
            //            connectionNoTransactionList.Add(db.ConnectionString, noTransactionConnection);
            //        }
            //        //noTransactionConnection.AddRef();

            //    }
            //    return noTransactionConnection;
            //}

            Transaction currentTransaction = Transaction.Current;

            if (currentTransaction == null)
                return null;

            //事务对象下多个db操作类型
            Dictionary<string, DatabaseConnectionWrapper> connectionList;
            DatabaseConnectionWrapper connection;

            lock (transactionConnections)
            {
                if (!transactionConnections.TryGetValue(currentTransaction, out connectionList))
                {
                    connectionList = new Dictionary<string, DatabaseConnectionWrapper>();
                    transactionConnections.Add(currentTransaction, connectionList);

                    currentTransaction.TransactionCompleted += OnTransactionCompleted;
                }
            }

            lock (connectionList)
            {
                //线程同步
                if (!connectionList.TryGetValue(db.ConnectionString, out connection))
                {
                    var dbConnection = db.GetNewOpenConnection(true);
                    connection = new DatabaseConnectionWrapper(dbConnection);
                    connectionList.Add(db.ConnectionString, connection);
                    //CallContext.LogicalSetData(ConnectionListKey, connectionList);
                }
                //connection.AddRef();
            }
            connection.IsTransactionConnection = true;
            return connection;
        }

        //public static void OnConnectionDisposed()
        //{
        //    lock (connectionNoTransactionList)
        //    {
        //        foreach (var connectionWrapper in connectionNoTransactionList.Values)
        //        {
        //            connectionWrapper.Dispose();
        //        }
        //        foreach (var connectionKeys in connectionNoTransactionList.Keys.ToList())
        //        {
        //            connectionNoTransactionList.Remove(connectionKeys);
        //        }
        //    }
        //}

        /// <summary>
        /// 允许从事务中拿到线程
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        static void OnTransactionCompleted(object sender, TransactionEventArgs e)
        {
            Dictionary<string, DatabaseConnectionWrapper> connectionList;
            
            lock (transactionConnections)
            {
                if (!transactionConnections.TryGetValue(e.Transaction, out connectionList))
                {
                    return;
                }
                transactionConnections.Remove(e.Transaction);
                //if (e.Transaction != null)
                //{
                //    e.Transaction.Dispose();
                //}
            }

            lock (connectionList)
            {
                foreach (var connectionWrapper in connectionList.Values)
                {
                    connectionWrapper.Dispose();
                }
                if (connectionList.Values.Count > 0)
                {
                    //CallContext.FreeNamedDataSlot(ConnectionListKey);
                }
            }
        }
    }
}
